
package com.star.redis;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisNode;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.JedisPoolConfig;

import java.util.ArrayList;
import java.util.List;


/**
 * @Author chaoyang_z
 * @Date 2019/8/17 0017
 * @Version V1.0
 **/
@ConditionalOnProperty(value = "redisSingle", havingValue = "true")
@Configuration
public class RedisClusterConfig {

    @Autowired
    private ClusterRedisProperties clusterRedisProperties;

    /**
     *  * 配置jedis连接池
     *  * @return
     *  
     */
    @Bean
    public JedisPoolConfig jedisPoolConfig() {
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxTotal(clusterRedisProperties.getMaxTotal());
        jedisPoolConfig.setMaxIdle(clusterRedisProperties.getMaxIdle());
        jedisPoolConfig.setMinIdle(clusterRedisProperties.getMinIdle());
        jedisPoolConfig.setMaxWaitMillis(clusterRedisProperties.getMaxWait());
        jedisPoolConfig.setTestOnBorrow(clusterRedisProperties.isTestOnBorrow());
        jedisPoolConfig.setTestOnReturn(clusterRedisProperties.isTestOnReturn());
        jedisPoolConfig.setTestWhileIdle(clusterRedisProperties.isTestWhileIdle());
        jedisPoolConfig.setTimeBetweenEvictionRunsMillis(clusterRedisProperties.getTimeBetweenEvictionRunsMillis());
        return jedisPoolConfig;
    }

    /**
     *  * redis集群配置
     *  * @return
     *  
     */
    @Bean
    public RedisClusterConfiguration redisClusterConfiguration() {

        RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration();
        redisClusterConfiguration.setMaxRedirects(clusterRedisProperties.getMaxRedirects());

        List<RedisNode> nodeList = new ArrayList<>();

        String[] cNodes = clusterRedisProperties.getNodes().split(",");
        //分割出集群节点
        for(String node : cNodes) {
            String[] hp = node.split(":");
            nodeList.add(new RedisNode(hp[0], Integer.parseInt(hp[1])));
        }
        redisClusterConfiguration.setClusterNodes(nodeList);

        return redisClusterConfiguration;
    }

    /**
     *  * 配置jedis连接工厂
     *  * @param redisClusterConfiguration
     *  * @param jedisPoolConfig
     *  * @return
     *  
     */
    @Bean
    public JedisConnectionFactory jedisConnectionFactory(RedisClusterConfiguration redisClusterConfiguration, JedisPoolConfig jedisPoolConfig) {
        JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(redisClusterConfiguration, jedisPoolConfig);
        jedisConnectionFactory.setTimeout(clusterRedisProperties.getConnectionTimeout());
        jedisConnectionFactory.setPassword(clusterRedisProperties.getPassword());
        return jedisConnectionFactory;
    }


    /**
     * 设置数据存入redis 的序列化方式
     *  redisTemplate序列化默认使用的jdkSerializeable
     *  存储二进制字节码，导致key会出现乱码，所以自定义序列化类
     */
    @Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

}

